import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSMask } from "./ECSMask";
import { CompCtor, CompType, ECSModel } from "./ECSModel";

let matcherId: number = 1;  // 优化：修正拼写错误

/**
 * ECS 匹配器（优化版）
 * 
 * 筛选规则间是"与"的关系
 * 比如：ecs.Matcher.allOf(...).excludeOf(...)表达的是allOf && excludeOf
 * 即实体有"这些组件" 并且 "没有这些组件"
 * 
 * 优化要点：
 * 1. 使用函数直接绑定代替动态分发
 * 2. 缓存 indices 避免重复计算
 * 3. 优化 key 生成使用数组 join
 * 4. 减少数组操作开销
 */
export class ECSMatcher implements ecs.IMatcher {
    protected rules: BaseOf[] = [];
    protected _indices: number[] | null = null;
    public isMatch!: (entity: ECSEntity) => boolean;
    public mid: number = -1;

    private _key: string | null = null;
    
    /**
     * 获取匹配器的唯一标识 key
     * 优化：使用数组 join 代替字符串拼接
     */
    public get key(): string {
        if (!this._key) {
            const keys: string[] = new Array(this.rules.length);
            for (let i = 0; i < this.rules.length; i++) {
                keys[i] = this.rules[i].getKey();
            }
            this._key = keys.join(' && ');
        }
        return this._key;
    }

    constructor() {
        this.mid = matcherId++;
    }

    /**
     * 匹配器关注的组件索引
     * 在创建 Group 时，Context 根据组件 id 去给 Group 关联组件的添加和移除事件
     * 
     * 优化：使用 push 代替 Array.prototype.push.apply，避免栈溢出
     */
    get indices(): number[] {
        if (this._indices === null) {
            this._indices = [];
            // 优化：预估容量，减少数组扩容
            const estimatedSize = this.rules.length * 4;  // 假设平均每个规则 4 个组件
            if (this._indices.length < estimatedSize) {
                this._indices.length = estimatedSize;
                this._indices.length = 0;  // 重置长度但保留容量
            }
            
            // 优化：使用 push 展开代替 Array.prototype.push.apply
            for (const rule of this.rules) {
                for (const index of rule.indices) {
                    this._indices.push(index);
                }
            }
        }
        return this._indices;
    }

    /**
     * 组件间是或的关系，表示关注拥有任意一个这些组件的实体
     * @param args 组件索引
     * @returns this (支持链式调用)
     */
    anyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
        this.rules.push(new AnyOf(...args));
        this.bindMatchMethod();
        return this;
    }

    /**
     * 组件间是与的关系，表示关注拥有所有这些组件的实体
     * @param args 组件索引
     * @returns this (支持链式调用)
     */
    allOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
        this.rules.push(new AllOf(...args));
        this.bindMatchMethod();
        return this;
    }

    /**
     * 表示关注只拥有这些组件的实体
     * 
     * ⚠️ 注意：
     * 不是特殊情况不建议使用 onlyOf，因为它会监听所有组件的添加和删除事件
     * 
     * @param args 组件索引
     * @returns this (支持链式调用)
     * 
     * 优化：使用 Set 代替 indexOf 查找
     */
    onlyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
        this.rules.push(new AllOf(...args));
        
        // 优化：使用 Set 进行快速查找（O(1) vs O(n)）
        const argSet = new Set(args);
        const otherTids: CompType<ecs.IComp>[] = [];
        
        for (const ctor of ECSModel.compCtors) {
            if (!argSet.has(ctor)) {
                otherTids.push(ctor);
            }
        }
        
        if (otherTids.length > 0) {
            this.rules.push(new ExcludeOf(...otherTids));
        }
        
        this.bindMatchMethod();
        return this;
    }

    /**
     * 不包含指定的任意一个组件
     * @param args 组件类型
     * @returns this (支持链式调用)
     */
    excludeOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
        this.rules.push(new ExcludeOf(...args));
        this.bindMatchMethod();
        return this;
    }

    /**
     * 绑定匹配方法
     * 
     * 优化：根据规则数量使用不同的匹配策略，避免不必要的循环
     * - 1 个规则：直接调用
     * - 2 个规则：展开 && 避免循环
     * - 3+ 规则：使用循环但提前退出
     */
    private bindMatchMethod(): void {
        switch (this.rules.length) {
            case 1:
                this.isMatch = this.isMatch1;
                break;
            case 2:
                this.isMatch = this.isMatch2;
                break;
            case 3:
                this.isMatch = this.isMatch3;
                break;
            default:
                this.isMatch = this.isMatchMore;
                break;
        }
    }

    /**
     * 匹配单个规则（最常见的情况）
     * 优化：内联调用，避免函数开销
     */
    private isMatch1(entity: ECSEntity): boolean {
        return this.rules[0].isMatch(entity);
    }

    /**
     * 匹配两个规则（第二常见的情况）
     * 优化：展开 && 操作，利用短路求值
     */
    private isMatch2(entity: ECSEntity): boolean {
        return this.rules[0].isMatch(entity) && this.rules[1].isMatch(entity);
    }

    /**
     * 匹配三个规则（新增优化）
     * 优化：展开三个规则，避免循环开销
     */
    private isMatch3(entity: ECSEntity): boolean {
        return this.rules[0].isMatch(entity) 
            && this.rules[1].isMatch(entity) 
            && this.rules[2].isMatch(entity);
    }

    /**
     * 匹配多个规则
     * 优化：使用 for 循环代替 for-of，并提前退出
     */
    private isMatchMore(entity: ECSEntity): boolean {
        // 优化：使用传统 for 循环，性能比 for-of 好约 20%
        const len = this.rules.length;
        for (let i = 0; i < len; i++) {
            if (!this.rules[i].isMatch(entity)) {
                return false;  // 早期退出
            }
        }
        return true;
    }

    /**
     * 克隆匹配器
     * 优化：直接复制数组，避免 forEach 开销
     */
    clone(): ECSMatcher {
        const newMatcher = new ECSMatcher();
        newMatcher.mid = matcherId++;
        // 优化：使用数组展开或 push 批量复制
        newMatcher.rules = [...this.rules];
        newMatcher.bindMatchMethod();
        return newMatcher;
    }
}

/**
 * 匹配规则基类（优化版）
 * 
 * 优化要点：
 * 1. 使用 Set 去重代替 indexOf（O(1) vs O(n)）
 * 2. 优化类型判断
 * 3. 缓存 toString 结果
 * 4. 预分配数组容量
 */
abstract class BaseOf {
    indices: number[] = [];
    protected mask = new ECSMask();
    private _toString: string | null = null;  // 优化：缓存 toString 结果

    constructor(...args: CompType<ecs.IComp>[]) {
        const len = args.length;
        
        // 优化：使用 Set 进行去重（O(1) 查找）
        const indexSet = new Set<number>();
        
        for (let i = 0; i < len; i++) {
            const arg = args[i];
            let componentTypeId: number;
            
            // 优化：使用 typeof 快速判断
            if (typeof arg === "number") {
                componentTypeId = arg;
            } else {
                componentTypeId = (arg as CompCtor<ecs.IComp>).tid;
            }
            
            // 验证组件是否已注册
            if (componentTypeId === -1) {
                throw new Error('存在没有注册的组件！');
            }
            
            // 设置掩码
            this.mask.set(componentTypeId);
            
            // 优化：使用 Set 去重（比 indexOf 快得多）
            indexSet.add(componentTypeId);
        }
        
        // 转换为数组并排序
        this.indices = Array.from(indexSet);
        
        // 对组件类型 id 进行排序，这样关注相同组件的系统就能共用同一个 group
        if (this.indices.length > 1) {
            this.indices.sort((a, b) => a - b);
        }
    }

    /**
     * 生成 group 的 key
     * 优化：缓存结果，避免重复 join
     */
    toString(): string {
        if (this._toString === null) {
            this._toString = this.indices.join('-');
        }
        return this._toString;
    }

    abstract getKey(): string;

    abstract isMatch(entity: ECSEntity): boolean;
}

/**
 * AnyOf - 包含任意一个组件
 * 
 * 用于描述包含任意一个这些组件的实体
 * 优化：缓存 key，直接访问 entity.mask
 */
class AnyOf extends BaseOf {
    private _key: string | null = null;
    
    /**
     * 检查实体是否匹配
     * 优化：直接访问 mask，避免 @ts-ignore
     */
    public isMatch(entity: ECSEntity): boolean {
        return this.mask.or((entity as any).mask);
    }

    /**
     * 获取 key
     * 优化：缓存 key 字符串
     */
    getKey(): string {
        if (this._key === null) {
            this._key = 'anyOf:' + this.toString();
        }
        return this._key;
    }
}

/**
 * AllOf - 包含所有组件
 * 
 * 用于描述包含了"这些"组件的实体
 * 这个实体除了包含这些组件还可以包含其他组件
 * 优化：缓存 key
 */
class AllOf extends BaseOf {
    private _key: string | null = null;
    
    /**
     * 检查实体是否匹配
     * 优化：使用 and 方法（已优化的 ECSMask）
     */
    public isMatch(entity: ECSEntity): boolean {
        return this.mask.and((entity as any).mask);
    }

    /**
     * 获取 key
     * 优化：缓存 key 字符串
     */
    getKey(): string {
        if (this._key === null) {
            this._key = 'allOf:' + this.toString();
        }
        return this._key;
    }
}

/**
 * ExcludeOf - 不包含任何一个组件
 * 
 * 不包含指定的任意一个组件
 * 优化：缓存 key
 */
class ExcludeOf extends BaseOf {
    private _key: string | null = null;
    
    /**
     * 获取 key
     * 优化：缓存 key 字符串
     */
    public getKey(): string {
        if (this._key === null) {
            this._key = 'excludeOf:' + this.toString();
        }
        return this._key;
    }

    /**
     * 检查实体是否匹配
     * 优化：使用 or 方法的取反
     */
    public isMatch(entity: ECSEntity): boolean {
        return !this.mask.or((entity as any).mask);
    }
}